home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / QNX.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  13KB  |  682 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)qnx.c    2.2 (Chris & John Downey) 8/7/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     qnx.c
  14. * module function:
  15.     QNX system interface module.
  16.  
  17.     Note that this module assumes the C86 compiler,
  18.     which is an ANSI compiler, rather than the standard
  19.     QNX compiler, which is not.
  20.  
  21. * history:
  22.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  23.     Originally by Tim Thompson (twitch!tjt)
  24.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  25.     Heavily modified by Chris & John Downey
  26.  
  27. ***/
  28.  
  29. /*
  30.  * QNX-specific include files.
  31.  *
  32.  * <stdio.h> etc. get included by "xvi.h".
  33.  */
  34. #include <io.h>
  35. #include <dev.h>
  36. #include <sys/stat.h>
  37. #include <timer.h>
  38. #include <tcap.h>
  39. #include <tcapkeys.h>
  40. #include <taskmsgs.h>
  41.  
  42. #include "xvi.h"
  43.  
  44. #define    PIPE_MASK_1    "/tmp/xvipipe1XXXXXX"
  45. #define    PIPE_MASK_2    "/tmp/xvipipe2XXXXXX"
  46. #define    EXPAND_MASK    "/tmp/xvexpandXXXXXX"
  47.  
  48. extern    int        tcap_row;
  49. extern    int        tcap_col;
  50.  
  51. int            can_scroll_area;
  52. void            (*up_func)(int, int, int);
  53. void            (*down_func)(int, int, int);
  54.  
  55. static    int        disp_inited = 0;
  56. static    unsigned    screen_colour = DEF_COLOUR;
  57. static    int        old_options;
  58.  
  59. static    bool_t        triggered;
  60.  
  61. static void
  62. catch_usr1(i)
  63. int    i;
  64. {
  65.     (void) signal(SIGUSR1, SIG_IGN);
  66.     triggered = TRUE;
  67. }
  68.  
  69. /*
  70.  * inchar() - get a character from the keyboard
  71.  */
  72. int
  73. inchar(timeout)
  74. long    timeout;
  75. {
  76.     register int    c;
  77.     bool_t        setsignal = FALSE;
  78.  
  79.     /*
  80.      * Set a timeout on input if asked to do so.
  81.      */
  82.     if (timeout != 0) {
  83.     /*
  84.      * Timeout value is in milliseconds, so we have to convert
  85.      * to 50 millisecond ticks, rounding up as we do it.
  86.      */
  87.     (void) signal(SIGUSR1, catch_usr1);
  88.     (void) set_timer(TIMER_SET_EXCEPTION, RELATIVE,
  89.             (int) ((timeout + 19) / 20),
  90.             SIGUSR1,
  91.             (char *) NULL);
  92.     setsignal = TRUE;
  93.     }
  94.  
  95.     flush_output();
  96.     for (;;) {
  97.     triggered = FALSE;
  98.  
  99.     c = term_key();
  100.  
  101.     if (triggered) {
  102.         return(EOF);
  103.     }
  104.  
  105.     if (c > 127) {
  106.         /*
  107.          * Must be a function key press.
  108.          */
  109.  
  110.         if (State != NORMAL) {
  111.         /*
  112.          * Function key pressed during insert
  113.          * or command line mode.
  114.          */
  115.         alert();
  116.         continue;
  117.         }
  118.  
  119.         switch (c) {
  120.         case KEY_F1: /* F1 key */
  121.         c = K_HELP;
  122.         break;
  123.         case KEY_HOME:
  124.         c = 'H';
  125.         break;
  126.         case KEY_END:
  127.         c = 'L';
  128.         break;
  129.         case KEY_PAGE_UP:
  130.         c = CTRL('B');
  131.         break;
  132.         case KEY_PAGE_DOWN:
  133.         c = CTRL('F');
  134.         break;
  135.         case KEY_UP:
  136.         c = K_UARROW;
  137.         break;
  138.         case KEY_LEFT:
  139.         c = K_LARROW;
  140.         break;
  141.         case KEY_RIGHT:
  142.         c = K_RARROW;
  143.         break;
  144.         case KEY_DOWN:
  145.         c = K_DARROW;
  146.         break;
  147.         case KEY_WORD_LEFT:
  148.         c = 'b';
  149.         break;
  150.         case KEY_WORD_RIGHT:
  151.         c = 'w';
  152.         break;
  153.         case KEY_INSERT:
  154.         c = 'i';
  155.         break;
  156.         case KEY_DELETE:
  157.         c = 'x';
  158.         break;
  159.         case KEY_RUBOUT:
  160.         c = '\b';
  161.         break;
  162.         case KEY_TAB:
  163.         c = '\t';
  164.         break;
  165.         }
  166.     }
  167.     if (setsignal)
  168.         (void) signal(SIGUSR1, SIG_IGN);
  169.     return(c);
  170.     }
  171.     /*NOTREACHED*/
  172. }
  173.  
  174. void
  175. sys_init()
  176. {
  177.     if (!disp_inited) {
  178.     term_load(stdin);
  179.     term_video_on();
  180.     }
  181.     if (strcmp(tcap_entry.term_name, "qnx") == 0) {
  182.     up_func = co_up;
  183.     down_func = co_down;
  184.     can_scroll_area = TRUE;
  185.     } else if (strncmp(tcap_entry.term_name, "vt100", 5) == 0) {
  186.     up_func = vt_up;
  187.     down_func = vt_down;
  188.     can_scroll_area = TRUE;
  189.     } else {
  190.     can_scroll_area = FALSE;
  191.     }
  192.  
  193.     /*
  194.      * Support different number of rows for VGA text modes.
  195.      */
  196.     if (tcap_entry.term_type == VIDEO_MAPPED) {
  197.     unsigned    console;
  198.     unsigned    row_col;
  199.  
  200.     console = fdevno(stdout);
  201.     row_col = video_get_size(console);
  202.     Rows = (row_col >> 8) & 0xff;
  203.     Columns = row_col & 0xff;
  204.     }
  205.  
  206.     sys_startv();
  207.     disp_inited = 1;
  208. }
  209.  
  210. static    int        pcmode;            /* display mode */
  211.  
  212. void
  213. sys_exit(r)
  214. int    r;
  215. {
  216.     if (disp_inited) {
  217.     term_cur(Rows - 1, 0);
  218.     sys_endv();
  219.     }
  220.     exit(r);
  221. }
  222.  
  223. /*
  224.  * Returns TRUE if file does not exist or exists and is writeable.
  225.  */
  226. bool_t
  227. can_write(file)
  228. char    *file;
  229. {
  230.     return(access(file, W_OK) == 0 || access(file, F_OK) != 0);
  231. }
  232.  
  233. bool_t
  234. exists(file)
  235. char *file;
  236. {
  237.     return(access(file, F_OK) == 0);
  238. }
  239.  
  240. /*
  241.  * Scroll an area on the console screen up by nlines.
  242.  * The number of lines is always positive, and
  243.  * we can assume we will not be called with
  244.  * parameters which would result in scrolling
  245.  * the entire window.
  246.  *
  247.  * Note that this routine will not be called unless
  248.  * can_scroll_area is TRUE, which is only the case
  249.  * for the console screen (i.e. term_name == "qnx").
  250.  */
  251. void
  252. co_up(start, end, nlines)
  253. int    start, end, nlines;
  254. {
  255.     char    *buf;
  256.     int        i;
  257.  
  258.     buf = malloc((unsigned) Columns * term_save_image(0, 0, NULL, 0));
  259.     if (buf == NULL)
  260.     return;
  261.  
  262.     for (i = start; i <= end - nlines; i++) {
  263.     term_save_image(i + nlines, 0, buf, Columns);
  264.     term_restore_image(i, 0, buf, Columns);
  265.     }
  266.  
  267.     for ( ; i <= end; i++) {
  268.     term_cur(i, 0);
  269.     term_clear(_CLS_EOL);
  270.     }
  271.  
  272.     free(buf);
  273. }
  274.  
  275. /*
  276.  * Scroll an area on the console screen down by nlines.
  277.  * The number of lines is always positive, and
  278.  * we can assume we will not be called with
  279.  * parameters which would result in scrolling
  280.  * the entire window.
  281.  *
  282.  * Note that this routine will not be called unless
  283.  * can_scroll_area is TRUE, which is only the case
  284.  * for the console screen (i.e. term_name == "qnx").
  285.  */
  286. void
  287. co_down(start, end, nlines)
  288. int    start, end, nlines;
  289. {
  290.     char    *buf;
  291.     int        i;
  292.  
  293.     buf = malloc((unsigned) Columns * term_save_image(0, 0, NULL, 0));
  294.     if (buf == NULL)
  295.     return;
  296.  
  297.     for (i = end; i >= start + nlines; --i) {
  298.     term_save_image(i - nlines, 0, buf, Columns);
  299.     term_restore_image(i, 0, buf, Columns);
  300.     }
  301.  
  302.     for ( ; i >= start; --i) {
  303.     term_cur(i, 0);
  304.     term_clear(_CLS_EOL);
  305.     }
  306.  
  307.     free(buf);
  308. }
  309.  
  310. /*
  311.  * Scroll an area on a vt100 terminal screen up by nlines.
  312.  * The number of lines is always positive, and we can assume
  313.  * we will not be called with parameters which would result
  314.  * in scrolling the entire window.
  315.  */
  316. void
  317. vt_up(start, end, nlines)
  318. int    start, end, nlines;
  319. {
  320.     int        count;
  321.  
  322.     (void) printf("\0337");                /* save cursor */
  323.     (void) printf("\033[%d;%dr", start + 1, end + 1);    /* set scroll region */
  324.     (void) printf("\033[%d;1H", end + 1);        /* goto bottom left */
  325.     for (count = 0; count < nlines; count++) {
  326.     putchar('\n');
  327.     }
  328.     (void) printf("\033[1;%dr", Rows);            /* set scroll region */
  329.     (void) printf("\0338");                /* restore cursor */
  330. }
  331.  
  332. /*
  333.  * Scroll an area on a vt100 terminal screen down by nlines.
  334.  * The number of lines is always positive, and we can assume
  335.  * we will not be called with parameters which would result
  336.  * in scrolling the entire window.
  337.  */
  338. void
  339. vt_down(start, end, nlines)
  340. int    start, end, nlines;
  341. {
  342.     int        count;
  343.  
  344.     (void) printf("\0337");                /* save cursor */
  345.     (void) printf("\033[%d;%dr", start + 1, end + 1);    /* set scroll region */
  346.     (void) printf("\033[%d;1H", start + 1);        /* goto top left */
  347.     for (count = 0; count < nlines; count++) {
  348.     fputs("\033[L", stdout);
  349.     }
  350.     (void) printf("\033[1;%dr", Rows);            /* set scroll region */
  351.     (void) printf("\0338");                /* restore cursor */
  352. }
  353.  
  354. int
  355. call_shell(sh)
  356. char    *sh;
  357. {
  358.     return(spawnlp(0, sh, sh, (char *) NULL));
  359. }
  360.  
  361. void
  362. alert()
  363. {
  364.     putchar('\007');
  365. }
  366.  
  367. void
  368. delay()
  369. {
  370.     (void) set_timer(TIMER_WAKEUP, RELATIVE, 2, 0, NULL);
  371. }
  372.  
  373. void
  374. outchar(c)
  375. int    c;
  376. {
  377.     char    cbuf[2];
  378.  
  379.     cbuf[0] = c;
  380.     cbuf[1] = '\0';
  381.     outstr(cbuf);
  382. }
  383.  
  384. void
  385. outstr(s)
  386. char    *s;
  387. {
  388.     term_type(-1, -1, s, 0, screen_colour);
  389. }
  390.  
  391. void
  392. flush_output()
  393. {
  394.     (void) fflush(stdout);
  395. }
  396.  
  397. void
  398. set_colour(c)
  399. int    c;
  400. {
  401.     screen_colour = (unsigned) c;
  402.     term_colour(screen_colour >> 8);
  403. }
  404.  
  405. void
  406. tty_goto(r, c)
  407. int    r, c;
  408. {
  409.     term_cur(r, c);
  410. }
  411.  
  412. void
  413. sys_startv()
  414. {
  415.     /*
  416.      * Turn off:
  417.      *    EDIT    to get "raw" mode
  418.      *    ECHO    to stop characters being echoed
  419.      *    MAPCR    to stop mapping of \r into \n
  420.      */
  421.     old_options = get_option(stdin);
  422.     set_option(stdin, old_options & ~(EDIT | ECHO | MAPCR));
  423. }
  424.  
  425. void
  426. sys_endv()
  427. {
  428.     term_cur(Rows - 1, 0);
  429.     set_colour(Pn(P_systemcolour));
  430.     erase_line();
  431.     flush_output();
  432.  
  433.     /*
  434.      * This flushes the typeahead buffer so that recall of previous
  435.      * commands will not work - this is desirable because some of
  436.      * the commands typed to vi (i.e. control characters) will
  437.      * have a deleterious effect if given to the shell.
  438.      */
  439.     flush_input(stdin);
  440.  
  441.     set_option(stdin, old_options);
  442. }
  443.  
  444. /*
  445.  * Construct unique name for temporary file,
  446.  * to be used as a backup file for the named file.
  447.  */
  448. char *
  449. tempfname(srcname)
  450. char    *srcname;
  451. {
  452.     char    *newname;        /* ptr to allocated new pathname */
  453.     char    *last_slash;        /* ptr to last slash in srcname */
  454.     char    *last_hat;        /* ptr to last slash in srcname */
  455.     int        tail_length;        /* length of last component */
  456.     int        head_length;        /* length up to (including) '/' */
  457.  
  458.     /*
  459.      * Obtain the length of the last component of srcname.
  460.      */
  461.     last_slash = strrchr(srcname, '/');
  462.     last_hat = strrchr(srcname, '^');
  463.     if ((last_slash == NULL) ||
  464.     (last_slash != NULL && last_hat != NULL && last_hat > last_slash)) {
  465.     last_slash = last_hat;
  466.     }
  467.  
  468.     /*
  469.      * last_slash now points at the last delimiter in srcname,
  470.      * or is NULL if srcname contains no delimiters.
  471.      */
  472.     if (last_slash != NULL) {
  473.     tail_length = strlen(last_slash + 1);
  474.     head_length = last_slash - srcname;
  475.     } else {
  476.     tail_length = strlen(srcname);
  477.     head_length = 0;
  478.     }
  479.  
  480.     /*
  481.      * We want to add ".tmp" onto the end of the name,
  482.      * and QNX restricts filenames to 16 characters.
  483.      * So we must ensure that the last component
  484.      * of the pathname is not more than 12 characters
  485.      * long, or truncate it so it isn't.
  486.      */
  487.     if (tail_length > 12)
  488.     tail_length = 12;
  489.  
  490.     /*
  491.      * Create the new pathname. We need the total length
  492.      * of the path as is, plus ".tmp" plus a null byte.
  493.      */
  494.     newname = alloc(head_length + tail_length + 5);
  495.     if (newname != NULL) {
  496.     (void) strncpy(newname, srcname, head_length + tail_length);
  497.     }
  498.  
  499.     {
  500.     char    *endp;
  501.     int    indexnum;
  502.  
  503.     endp = newname + head_length + tail_length;
  504.     indexnum = 0;
  505.     do {
  506.         /*
  507.          * Keep trying this until we get a unique file name.
  508.          */
  509.         if (indexnum > 0) {
  510.         (void) sprintf(endp, ".%03d", indexnum);
  511.         } else {
  512.         (void) strcpy(endp, ".tmp");
  513.         }
  514.         indexnum++;
  515.     } while (access(newname, 0) == 0 && indexnum < 1000);
  516.     }
  517.  
  518.     return(newname);
  519. }
  520.  
  521. /*
  522.  * Fake out a pipe by writing output to temp file, running a process with
  523.  * i/o redirected from this file to another temp file, and then reading
  524.  * the second temp file back in.
  525.  */
  526. bool_t
  527. sys_pipe(cmd, writefunc, readfunc)
  528. char    *cmd;
  529. int    (*writefunc) P((FILE *));
  530. long    (*readfunc) P((FILE *));
  531. {
  532.     Flexbuf        cmdbuf;
  533.     static char    *args[] = { NULL, "+s", NULL, NULL };
  534.     char        *temp1;
  535.     char        *temp2;
  536.     char        buffer[512];
  537.     FILE        *fp;
  538.     bool_t        retval = FALSE;
  539.  
  540.     if (Ps(P_shell) == NULL) {
  541.     return(FALSE);
  542.     }
  543.     args[0] = Ps(P_shell);
  544.  
  545.     temp1 = mktemp(PIPE_MASK_1);
  546.     temp2 = mktemp(PIPE_MASK_2);
  547.  
  548.     if (temp1 == NULL || temp2 == NULL) {
  549.     return(FALSE);
  550.     }
  551.  
  552.     /*
  553.      * At this stage we are comitted; any failures must go through
  554.      * the cleanup code at the end of the routine.
  555.      */
  556.  
  557.     sys_endv();
  558.  
  559.     flexnew(&cmdbuf);
  560.     (void) lformat(&cmdbuf, "%s < %s > %s", cmd, temp1, temp2);
  561.     args[2] = flexgetstr(&cmdbuf);
  562.  
  563.     fp = fopen(temp1, "w+");
  564.     if (fp == NULL) {
  565.     retval = FALSE;
  566.     goto ret;
  567.     }
  568.  
  569.     (void) (*writefunc)(fp);
  570.     (void) fclose(fp);
  571.  
  572.     if (createv(buffer, 0, -1, 0, BEQUEATH_TTY, 0, args, NULL) != 0) {
  573.     retval = FALSE;
  574.     goto ret;
  575.     }
  576.  
  577.     fp = fopen(temp2, "r");
  578.     if (fp == NULL) {
  579.     retval = FALSE;
  580.     goto ret;
  581.     }
  582.  
  583.     (void) (*readfunc)(fp);
  584.     (void) fclose(fp);
  585.  
  586.     retval = TRUE;
  587.  
  588. ret:
  589.     flexdelete(&cmdbuf);
  590.  
  591.     (void) remove(temp1);
  592.     (void) remove(temp2);
  593.     free(temp1);
  594.     free(temp2);
  595.  
  596.     sys_startv();
  597.  
  598.     return(retval);
  599. }
  600.  
  601. /*
  602.  * Expand filename.
  603.  * Have to do this using the shell, using a /tmp filename in the vain
  604.  * hope that it will be on a ramdisk and hence reasonably fast.
  605.  */
  606. char *
  607. fexpand(name)
  608. char    *name;
  609. {
  610.     static char    meta[] = "*?";
  611.     int        has_meta;
  612.     static char    *args[] = { NULL, "+s", NULL, NULL };
  613.     static char    *io[4];
  614.     Flexbuf    cmdbuf;
  615.     char    *temp = NULL;
  616.     FILE    *fp;
  617.     static char    newname[256];
  618.     char    *cp;
  619.  
  620.     if (name == NULL || *name == '\0') {
  621.     return(name);
  622.     }
  623.  
  624.     has_meta = FALSE;
  625.     for (cp = meta; *cp != '\0'; cp++) {
  626.     if (strchr(name, *cp) != NULL) {
  627.         has_meta = TRUE;
  628.         break;
  629.     }
  630.     }
  631.     if (!has_meta) {
  632.     return(name);
  633.     }
  634.  
  635.     if (Ps(P_shell) == NULL) {
  636.     goto fail;
  637.     }
  638.     args[0] = Ps(P_shell);
  639.  
  640.     temp = mktemp(EXPAND_MASK);
  641.  
  642.     if (temp == NULL) {
  643.     goto fail;
  644.     }
  645.  
  646.     flexnew(&cmdbuf);
  647.     (void) lformat(&cmdbuf, "echo %s > %s", name, temp);
  648.     args[2] = flexgetstr(&cmdbuf);
  649.  
  650.     io[0] = io[1] = io[2] = "$tty99";
  651.     if (createv(NULL, 0, -1, 0, 0, 0, args, NULL) != 0) {
  652.     goto fail;
  653.     }
  654.     flexdelete(&cmdbuf);
  655.  
  656.     fp = fopen(temp, "r");
  657.     if (fp == NULL) {
  658.     goto fail;
  659.     }
  660.  
  661.     if (fgets(newname, sizeof(newname), fp) == NULL) {
  662.     (void) fclose(fp);
  663.     goto fail;
  664.     }
  665.     cp = strchr(newname, '\n');
  666.     if (cp != NULL) {
  667.     *cp = '\0';
  668.     }
  669.  
  670.     (void) fclose(fp);
  671.     (void) remove(temp);
  672.     free(temp);
  673.  
  674.     return(newname);
  675.     
  676. fail:
  677.     if (temp != NULL) {
  678.     free(temp);
  679.     }
  680.     return(name);
  681. }
  682.